/**
 * @file    main.c 
 * @author  18408107475@163.com
 * @version V1.0.0
 * @date    2025-07-23
 * @brief   FreeRTOS多任务示例（LED闪烁+按键控制蜂鸣器）
 * @details 
 * 硬件配置：
 *   - 主控芯片：STM32F10x系列（如STM32F103C8T6）
 *   - 外设：
 *     - 绿色LED（PE5）：系统运行状态指示
 *     - 红色LED（PB5）：错误状态指示
 *     - 蜂鸣器：通过GPIO控制（具体引脚由BEEP_STD_Config.h定义）
 *     - 按键KEY1（PE3）：控制蜂鸣器开关（上拉输入，按下为低电平）
 *   - 连接说明：
 *     - LED采用共阳接法（阳极接3.3V，阴极接GPIO，低电平点亮）
 *     - 按键采用上拉输入（默认高电平，按下接地为低电平）
 * 
 * 软件特性：
 *   - 基于FreeRTOS实现多任务并发：
 *     - 绿色LED任务：最高优先级，1Hz周期闪烁
 *     - 红色LED任务：中等优先级，1Hz周期闪烁
 *     - 蜂鸣器任务：最低优先级，按键触发控制
 *   - 任务间通过句柄实现挂起/恢复控制
 *   - 硬件初始化集中管理，提高代码复用性
 */

/* Includes ------------------------------------------------------------------*/
/* 标准库头文件 */
#include <stdio.h>              // 提供标准输入输出功能（用于串口调试输出）

/* FreeRTOS内核头文件 */
#include "FreeRTOS.h"           // FreeRTOS核心配置和类型定义
#include "task.h"               // 任务管理API（创建/删除/延时等）
#include "queue.h"              // 队列管理API（当前未使用，保留供扩展）
#include "semphr.h"             // 信号量管理API（用于互斥锁实现）

/* 项目自定义头文件 */
#include "LED_STD_Config.h"     // LED硬件控制接口（初始化/亮灭控制）
#include "BEEP_STD_Config.h"    // 蜂鸣器控制接口（初始化/开关控制）
#include "USART1_Config.h"      // 串口调试接口（配置/格式化输出）
#include "Delay.h"              // 毫秒级延时函数（基于SysTick实现）

/* STM32标准外设库 */
#include "stm32f10x.h"          // STM32F10x系列MCU寄存器定义

/* 任务优先级配置（数值越大优先级越高） */
#define mainGREEN_LED_TASK_PRIORITY   (tskIDLE_PRIORITY + 3)  // 绿色LED任务（最高）
#define mainRED_LED_TASK_PRIORITY     (tskIDLE_PRIORITY + 2)  // 红色LED任务（中等）
#define mainBEEP_TASK_PRIORITY        (tskIDLE_PRIORITY + 1)  // 蜂鸣器任务（最低）

/* 按键KEY1硬件配置 */
#define KEY1_CLK     RCC_APB2Periph_GPIOE  // KEY1时钟（GPIOE）
#define KEY1_PORT    GPIOE                 // KEY1端口
#define KEY1_PIN     GPIO_Pin_3            // KEY1引脚（PE3）

/* 静态函数声明 */
static void prvKey1_Config(void);          // KEY1初始化（上拉输入）
static void prvHardwareConfig(void);      // 硬件集中初始化

/* 全局变量定义 */
TaskHandle_t Green_LedTaskHandle = NULL;  // 绿色LED任务句柄
TaskHandle_t Red_LedTaskHandle = NULL;    // 红色LED任务句柄
SemaphoreHandle_t g_mutex_led = NULL;     // LED控制互斥锁

/**
 * @brief  绿色LED任务函数
 * @param  pvParameters 任务参数（未使用）
 * @note   任务行为：
 *         1. 启动时打印配置信息
 *         2. 循环内：
 *            - 获取互斥锁
 *            - 打印状态信息
 *            - 释放互斥锁
 *            - LED亮500ms → 灭500ms（1Hz闪烁）
 *         3. 使用FreeRTOS延时函数释放CPU
 */
void vGreen_Led_Task(void *pvParameters)
{
    /* 任务初始化 */
    USART1_Printf("Green Led Task Config!!!\n\r");

    /* 任务主循环 */
    for(;;){
        /* 进入临界区（获取互斥锁）*/
        xSemaphoreTake(g_mutex_led, portMAX_DELAY);
        
        /* 任务状态输出 */
        USART1_Printf("Green Led running!!!\n\r");
        
        /* 退出临界区（释放互斥锁）*/
        xSemaphoreGive(g_mutex_led);
        
        /* LED控制段 */
        Green_Led_ON();               // 点亮LED
        USART1_Printf("Green ON!!!\n\r");
        vTaskDelay(pdMS_TO_TICKS(500)); // 延时500ms
        
        Green_Led_OFF();              // 熄灭LED
        USART1_Printf("Green OFF!!!\n\r");
        vTaskDelay(pdMS_TO_TICKS(500)); // 再延时500ms
    }
}

/**
 * @brief  红色LED任务函数
 * @param  pvParameters 任务参数（未使用）
 * @note   任务行为：
 *         1. 启动时打印配置信息
 *         2. 循环内：
 *            - 获取互斥锁
 *            - 打印状态信息
 *            - 释放互斥锁
 *            - LED灭500ms → 亮500ms（1Hz闪烁）
 *         3. 与绿色任务共享互斥锁
 */
void vRed_Led_Task(void *pvParameters)
{
    /* 任务初始化 */
    USART1_Printf("Red Led Task Config!!!\n\r");

    /* 任务主循环 */
    for(;;){
        /* 进入临界区（获取互斥锁）*/
        xSemaphoreTake(g_mutex_led, portMAX_DELAY);
        
        /* 任务状态输出 */
        USART1_Printf("Red Led running!!!\n\r");

        /* 退出临界区（释放互斥锁）*/
        xSemaphoreGive(g_mutex_led);
        
        /* LED控制段 */
        Red_Led_OFF();               // 熄灭LED
        USART1_Printf("Red OFF!!!\n\r");
        vTaskDelay(pdMS_TO_TICKS(500)); // 延时500ms
        
        Red_Led_ON();                // 点亮LED
        USART1_Printf("Red ON!!!\n\r");
        vTaskDelay(pdMS_TO_TICKS(500)); // 再延时500ms
    }
}

/**
 * @brief  蜂鸣器控制任务
 * @param  pvParameters 任务参数（未使用）
 * @note   任务行为：
 *         1. 启动时打印配置信息
 *         2. 循环内：
 *            - 检测按键状态（低电平触发）
 *            - 按键按下时启动蜂鸣器
 *            - 检测按键释放（带消抖）
 *            - 释放后关闭蜂鸣器
 *            - 自我挂起（需外部唤醒）
 */
void vBuzer_Task(void *pvParameters)
{
    /* 任务初始化 */
    USART1_Printf("Buzzer Config!!!\n\r");  

    /* 任务主循环 */
    for(;;){
        /* 状态输出 */
        USART1_Printf("Buzzer running!!!\n\r");
        
        /* 按键检测 */
        if(!GPIO_ReadInputDataBit(KEY1_PORT, KEY1_PIN)){
            /* 按键按下处理 */
            Beep_ON();  // 启动蜂鸣器
            
            /* 等待按键释放（带消抖）*/
            while(!GPIO_ReadInputDataBit(KEY1_PORT, KEY1_PIN)){
                vTaskDelay(10);  // 10ms延时消抖
            }
            
            /* 按键释放处理 */
            Beep_OFF(); // 关闭蜂鸣器
        }
        
        /* 任务挂起（需外部唤醒）*/
        vTaskSuspend(NULL); 
    }
}

/**
 * @brief  主函数
 * @retval int 程序状态码（实际不会返回）
 * @note   执行流程：
 *         1. 配置中断优先级分组
 *         2. 初始化硬件
 *         3. 创建三个任务
 *         4. 创建互斥锁
 *         5. 启动调度器
 */
int main(void)
{
    /* 中断优先级配置（FreeRTOS推荐分组4）*/
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
    
    /* 硬件初始化 */
    prvHardwareConfig();

    /* 任务创建状态变量 */
    BaseType_t xReturned;  
    
    /* 创建绿色LED任务 */
    xReturned = xTaskCreate(
        vGreen_Led_Task,       // 任务函数指针
        "Green_Led",           // 任务名称
        configMINIMAL_STACK_SIZE, // 任务栈大小
        NULL,                  // 任务参数
        mainGREEN_LED_TASK_PRIORITY, // 优先级
        &Green_LedTaskHandle   // 任务句柄
    );
    
    /* 创建蜂鸣器任务 */
    xTaskCreate(
        vBuzer_Task, 
        "Key control Beep", 
        configMINIMAL_STACK_SIZE, 
        NULL, 
        mainBEEP_TASK_PRIORITY, 
        NULL
    );

    /* 创建红色LED任务 */
    xTaskCreate(
        vRed_Led_Task,
        "Red_Led",
        configMINIMAL_STACK_SIZE,
        NULL,
        mainRED_LED_TASK_PRIORITY,
        &Red_LedTaskHandle
    );

    /* 任务创建检查 */
    if(xReturned != pdPASS){
        /* 创建失败处理（红色LED常亮）*/
        for(;;){
            Red_Led_ON();
            vTaskDelay(pdMS_TO_TICKS(100));
        }
    }

    /* 创建互斥锁 */
    g_mutex_led = xSemaphoreCreateMutex();

    /* 启动调度器 */
    vTaskStartScheduler();

    /* 调度器启动后不会执行到这里 */
    while (1) { /* 死循环 */ }
}

/**
 * @brief  KEY1初始化
 * @note   配置PE3为上拉输入模式
 */
static void prvKey1_Config(void)
{
    /* 使能GPIOE时钟 */
    RCC_APB2PeriphClockCmd(KEY1_CLK, ENABLE);

    /* GPIO初始化结构体 */
    GPIO_InitTypeDef GPIO_InitStructure = {
        .GPIO_Mode  = GPIO_Mode_IPU,    // 上拉输入
        .GPIO_Pin   = KEY1_PIN,         // PE3引脚
        .GPIO_Speed = GPIO_Speed_50MHz  // 输入模式下无效
    };

    /* 应用配置 */
    GPIO_Init(KEY1_PORT, &GPIO_InitStructure);
}

/**
 * @brief  硬件集中初始化
 * @note   初始化顺序：
 *         1. LED
 *         2. 蜂鸣器
 *         3. 按键
 *         4. 串口
 */
static void prvHardwareConfig(void)
{
    LED_STD_Config();        // LED初始化
    BEEP_STD_Config();      // 蜂鸣器初始化
    prvKey1_Config();        // 按键初始化
    USART1_Config(115200);  // 串口初始化（115200波特率）
}

/************************ (C) COPYRIGHT  END OF FILE************************/